﻿using log4net.Appender;
using log4net.Config;
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace Waiyun.WebApi
{
    /// <summary>
    /// 日志处理类，对log4net进行了包装
    /// </summary>
    public static class Logger
    {
        private static string s_logOutputDirectory;
        private static Dictionary<string, log4net.ILog> s_loggerDict = new Dictionary<string, log4net.ILog>();
        private static IAppender s_allAppender;

        private static readonly string TAG_ALL = "ALL";
        private static object s_lockObj = new object();

        /// <summary>
        /// 获得log4net的日志器
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        private static log4net.ILog GetLog(string tag)
        {
            if (s_loggerDict.ContainsKey(tag))
            {
                return s_loggerDict[tag];
            }
            else
            {
                lock (s_lockObj)
                {
                    if (string.IsNullOrEmpty(s_logOutputDirectory))
                    {
                        return null;//
                        //InitByLogDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs\\"));
                    }

                    if (s_loggerDict.ContainsKey(tag))
                    {
                        return s_loggerDict[tag];
                    }
                    log4net.ILog log = log4net.LogManager.GetLogger(tag);
                    log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)log.Logger;
                    logger.Level = logger.Hierarchy.LevelMap["ALL"];
                    if (!string.Equals(tag, TAG_ALL))
                    {
                        logger.AddAppender(GetRollingFileAppender(s_logOutputDirectory, tag));
                    }
                    logger.AddAppender(s_allAppender);
                    //logger.AddAppender(GetConsoleAppender(tag));
                    s_loggerDict.Add(tag, log);
                    return log;
                }
            }
        }

        /// <summary>
        ///  根据日志路径初始化
        /// </summary>
        /// <param name="directory"></param>
        public static void InitByLogDirectory(string directory)
        {
            if (string.IsNullOrEmpty(s_logOutputDirectory))
            {
                BasicConfigurator.Configure(GetConsoleAppender());

                s_logOutputDirectory = directory;
                s_allAppender = GetRollingFileAppender(s_logOutputDirectory, TAG_ALL);
            }
        }

        /// <summary>
        /// 使用文本记录异常日志
        /// </summary>
        public static RollingFileAppender GetRollingFileAppender(string logDirectory, string tag)
        {
            RollingFileAppender fileAppender = new RollingFileAppender();
            fileAppender.Name = string.Format("{0}Appender", tag);
            fileAppender.File = logDirectory;// string.Format("{0}{1}\\", logDirectory, tag);
            fileAppender.AppendToFile = true;
            fileAppender.StaticLogFileName = false;
            fileAppender.DatePattern = string.Format("yyyy-MM-dd\"\\\\{0}.log\"", tag);  //"yyyy-MM-dd\"\\.log\"";
            fileAppender.RollingStyle = RollingFileAppender.RollingMode.Composite;
            fileAppender.MaxFileSize = 1024 * 1024;
            fileAppender.MaxSizeRollBackups = 1024;
            fileAppender.LockingModel = new log4net.Appender.FileAppender.MinimalLock();

            PatternLayout patternLayout = new PatternLayout();
            if (!string.Equals(tag, TAG_ALL, StringComparison.CurrentCultureIgnoreCase))
            {
                patternLayout.ConversionPattern = "%d [%t] %p %m %newline";
            }
            else
            {
                patternLayout.ConversionPattern = "%d [%t] %p %logger %m %newline";
            }
            patternLayout.ActivateOptions();
            fileAppender.Layout = patternLayout;

            //选择UTF8编码，确保中文不乱码。
            fileAppender.Encoding = Encoding.UTF8;

            fileAppender.ActivateOptions();
            return fileAppender;
        }

        public static ConsoleAppender GetConsoleAppender()
        {
            ConsoleAppender appender = new ConsoleAppender();
            appender.Name = "ConsoleAppender";

            PatternLayout patternLayout = new PatternLayout();
            patternLayout.ConversionPattern = "%d  [%t] %p  %logger %m %newline";
            patternLayout.ActivateOptions();
            appender.Layout = patternLayout;

            appender.ActivateOptions();
            return appender;
        }

        #region info
        public static void Info(string message)
        {
            InfoToTag(TAG_ALL, message);
        }

        /// <summary>
        /// 信息日志
        /// </summary>
        /// <param name="tag">获取信息Logger的名字</param>
        /// <param name="message">信息消息</param>
        public static void InfoToTag(string tag, string message)
        {
            log4net.ILog loginfo = GetLog(tag);
            if (loginfo == null)
            {
                return;
            }
            loginfo.Info(message);
        }
        #endregion

        #region debug
        public static void Debug(string message)
        {
            DebugToTag(TAG_ALL, message);
        }

        /// <summary>
        /// 输出日志
        /// </summary>
        /// <param name="tag">获取输出Logger的名字</param>
        /// <param name="message">输出信息</param>
        public static void DebugToTag(string tag, string message)
        {
#if DEBUG
            log4net.ILog logdebug = GetLog(tag);
            if (logdebug == null)
            {
                return;
            }
            logdebug.Debug(message);
#endif
        }
        #endregion

        #region warning
        public static void Warning(string message)
        {
            WarningToTag(TAG_ALL, message);
        }
        /// <summary>
        /// 警告日志
        /// </summary>
        /// <param name="tag">获取警告Logger的名字</param>
        /// <param name="message">警告信息</param>
        public static void WarningToTag(string tag, string message)
        {
            log4net.ILog logwarning = GetLog(tag);
            if (logwarning == null)
            {
                return;
            }
            logwarning.Warn(message);
        }
        #endregion

        #region error
        public static void Error(string message)
        {
            ErrorToTag(TAG_ALL, message);
        }

        /// <summary>
        /// 错误日志
        /// </summary>
        /// <param name="tag">获取错误logger的名字</param>
        /// <param name="message">错误消息</param>
        public static void ErrorToTag(string tag, string message)
        {
            log4net.ILog logerror = GetLog(tag);
            if (logerror == null)
            {
                return;
            }
            logerror.Error(message);
        }
        #endregion


        public static List<LogItem> GetList(DateTime date, List<int> levels)
        {
            List<LogItem> items = new List<LogItem>();
            string logFilePath = string.Format("{0}{1}\\All.log", s_logOutputDirectory, date.ToString("yyyy-MM-dd"));
            if (System.IO.File.Exists(logFilePath))
            {
                using (FileStream fileStream = new FileStream(logFilePath, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader reader = new StreamReader(fileStream))
                    {
                        string line = reader.ReadLine();
                        while (line != null)
                        {
                            int firstBlankIndex = line.IndexOf(' ');
                            if (firstBlankIndex == 10)
                            {
                                int secondBlankIndex = line.IndexOf(' ', firstBlankIndex + 1);
                                int thirdBlankIndex = line.IndexOf(' ', secondBlankIndex + 1);
                                int fourthBlankIndex = line.IndexOf(' ', thirdBlankIndex + 1);

                                LogItem item = new LogItem();
                                item.Date = Convert.ToDateTime(line.Substring(0, secondBlankIndex).Split(new char[]{','}).First());
                                string level = line.Substring(thirdBlankIndex + 1, fourthBlankIndex - thirdBlankIndex - 1);
                                switch (level)
                                {
                                    case "ERROR":
                                        item.Level = 3;
                                        break;
                                    case "WARN":
                                        item.Level = 2;
                                        break;
                                    default:
                                        item.Level = 1;
                                        break;
                                }
                                item.Summary = line.Substring(fourthBlankIndex + 1, line.Length - fourthBlankIndex - 1);

                                if (levels.Contains(item.Level))
                                {
                                    items.Add(item);
                                }
                            }
                            
                            line = reader.ReadLine();
                        }
                    }
                }
            }
            return items;
        }

        public class LogItem
        {
            public DateTime Date { get; set; }
            public string Summary { get; set; }
            public string Tag { get; set; }
            public int Level { get; set; }
        }

        //public static void ErrorTry(string logTag, Action @delegate)
        //{
        //    try
        //    {
        //        @delegate();
        //    }
        //    catch (Exception ex)
        //    {
        //        ErrorToTag(logTag)
        //    }
        //}
    }
}
